package com.andnnl.lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by chenss on 2019/8/30.
 */
public class LockConditionTest {
    public static void main(String[] args) {
        PrintABCUsingCondition printABC = new PrintABCUsingCondition();
        new Thread(() -> printABC.printA()).start();
        new Thread(() -> printABC.printB()).start();
        new Thread(() -> printABC.printC()).start();
    }
}

class PrintABCUsingCondition {
    private Lock lock = new ReentrantLock();
    private Condition conditionA = lock.newCondition();
    private Condition conditionB = lock.newCondition();
    private Condition conditionC = lock.newCondition();
    private int state = 0;
    //private int attempts = 0;

    public void printB() {
        for (int i = 0; i < 2; i++) {
            print("B", 1, conditionB, conditionC);
//            try {
//                Thread.sleep(1000);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
        }
    }

    public void printA() {
        for (int i = 0; i < 2; i++) {
//            try {
//                Thread.sleep(1000);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            print("A", 0, conditionA, conditionB);
        }
    }

    public void printC() {
        for (int i = 0; i < 2; i++) {
            print("C", 2, conditionC, conditionA);
//            try {
//                Thread.sleep(1000);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
        }

    }

    private void print(String name, int currentState, Condition currentCondition, Condition nextCondition) {

            lock.lock();
            try {
                //System.out.println(Thread.currentThread().getName()+" try to print "+name+", attempts : "+(++attempts));
                while (state % 3 != currentState) {
//                    currentCondition.await();
                     currentCondition.await(10000, TimeUnit.MILLISECONDS);
                }
                System.out.println(Thread.currentThread().getName() + " print " + name);
                state++;
//                i++;

                nextCondition.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }

    }
}

